package drds.data_propagate.binlog_event.binlog_event.load_infile_replication;

import drds.data_propagate.binlog_event.Buffer;
import drds.data_propagate.binlog_event.binlog_event.Header;
import drds.data_propagate.binlog_event.binlog_event.binlog_management.FormatDescriptionEvent;
import drds.data_propagate.binlog_event.binlog_event.statement_based_replication_events.QueryEvent;
import lombok.Getter;
import lombok.Setter;

import java.io.IOException;

/**
 * Event responsible for LOAD DATA execution, it similar decode Query_log_event but
 * before executing the queryString it substitutes original filename in LOAD DATA
 * queryString with taskId of temporary file.
 * <ul>
 * <li>4 bytes. The ID of the file decode load.</li>
 * <li>4 bytes. The start readedIndex within the statement for filename
 * substitution.</li>
 * <li>4 bytes. The end readedIndex within the statement for filename
 * substitution.</li>
 * <li>1 byte. How decode handle duplicates: LOAD_DUP_ERROR = 0, LOAD_DUP_IGNORE =
 * 1, LOAD_DUP_REPLACE = 2</li>
 * </ul>
 */
public final class ExecuteLoadQueryEvent extends QueryEvent {

    /*
     * Elements of this enum describe how LOAD DATA handles duplicates.
     */
    public static final int load_dup_error = 0;
    public static final int load_dup_ignore = load_dup_error + 1;
    public static final int load_dup_replace = load_dup_ignore + 1;
    /* ELQ = "Execute Load Query" */
    public static final int elq_file_id_offset = query_header_length;
    public static final int elq_fn_pos_start_offset = elq_file_id_offset + 4;
    public static final int elq_fn_pos_end_offset = elq_file_id_offset + 8;
    public static final int elq_dup_handling_offset = elq_file_id_offset + 12;
    /**
     * file_id of temporary file
     */
    @Setter
    @Getter
    private long fileId;
    /**
     * pointer decode the part of the queryString that should be substituted
     */
    @Setter
    @Getter
    private int fnPosStart;
    /**
     * pointer decode the end of this part of queryString
     */
    @Setter
    @Getter
    private int fnPosEnd;
    /**
     * We have decode store eventType of duplicateFromEffectiveInitialIndexOffset
     * handling explicitly, because for LOAD DATA it also depends on LOCAL option.
     * And this part of queryString will be rewritten during replication so this
     * information may be lost...
     */
    @Setter
    @Getter
    private int dupHandling;

    public ExecuteLoadQueryEvent(Header header, Buffer buffer, FormatDescriptionEvent formatDescriptionEvent)
            throws IOException {
        super(header, buffer, formatDescriptionEvent);

        buffer.newReadedIndex(formatDescriptionEvent.commonHeaderLength + elq_file_id_offset);

        fileId = buffer.getNextLittleEndian32UnsignedLong(); // ELQ_FILE_ID_OFFSET
        fnPosStart = (int) buffer.getNextLittleEndian32UnsignedLong(); // ELQ_FN_POS_START_OFFSET
        fnPosEnd = (int) buffer.getNextLittleEndian32UnsignedLong(); // ELQ_FN_POS_END_OFFSET
        dupHandling = buffer.getNext8SignedInt(); // ELQ_DUP_HANDLING_OFFSET

        final int len = queryString.length();
        if (fnPosStart > len || fnPosEnd > len || dupHandling > load_dup_replace) {
            throw new IOException(
                    String.format("Invalid ExecuteLoadQueryEvent: fn_pos_start=%d, " + "fn_pos_end=%d, dup_handling=%d",
                            fnPosStart, fnPosEnd, dupHandling));
        }
    }
}
